#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring
stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jint
nativeUpdateJavaValue(JNIEnv *env, jobject thiz,
                                                        jstring class_name, jstring field_name) {
    char* pClassName = const_cast<char *>(env->GetStringUTFChars(class_name, NULL));
    char* pFieldName = const_cast<char *>(env->GetStringUTFChars(field_name, NULL));
    jclass clazz = env->FindClass(pClassName);
    //jclass clazz = env->GetObjectClass(thiz);
    jfieldID field = env->GetFieldID(clazz, pFieldName, "Ljava/lang/String;");
    if (field == NULL){
        return -1;
    }
    //jobject fieldObj = env->GetObjectField(thiz, field);
    std::string strRes = "C++ 设置属性";
    jstring jsRes = env->NewStringUTF(strRes.c_str());
    env->SetObjectField(thiz, field, jsRes);
    env->ReleaseStringUTFChars(class_name, pClassName);
    env->ReleaseStringUTFChars(field_name, pFieldName);
    return 0;
}


extern "C"
JNIEXPORT jint
nativeCallJavaMethod(JNIEnv *env, jobject thiz,
                    jstring class_name, jstring method_name) {
    // TODO: implement nativeCallJavaMethod()
    char* pClassName = const_cast<char *>(env->GetStringUTFChars(class_name, NULL));
    char* pMethodName = const_cast<char *>(env->GetStringUTFChars(method_name, NULL));
    //jclass clazz = env->GetObjectClass(thiz);
    jclass clazz = env->FindClass(pClassName);
    jmethodID methodId = env->GetMethodID(clazz, pMethodName, "(Ljava/lang/String;)V");
    if (methodId == NULL){
        return -1;
    }
    std::string strArgs = "C++传递参数";
    jstring jsArg = env->NewStringUTF(strArgs.c_str());
    env->CallVoidMethod(thiz, methodId, jsArg);
    env->ReleaseStringUTFChars(class_name, pClassName);
    env->ReleaseStringUTFChars(method_name, pMethodName);
    return 0;
}

extern "C"
JNIEXPORT jobject
nativeCreateObject(JNIEnv *env, jobject thiz, jclass t_class,
                    jint age, jstring name, jstring addr) {
    jmethodID methodID = env->GetMethodID(t_class, "<init>", "(ILjava/lang/String;Ljava/lang/String;)V");
    jobject obj = env->NewObject(t_class, methodID, age, name, addr);
    return obj;
}


static JNINativeMethod getMethods[] = {
        {"stringFromJNI","()Ljava/lang/String;",(void*)stringFromJNI},
        {"nativeUpdateJavaValue","(Ljava/lang/String;Ljava/lang/String;)I",(void*)nativeUpdateJavaValue},
        {"nativeCallJavaMethod","(Ljava/lang/String;Ljava/lang/String;)I",(void*)nativeCallJavaMethod},
        {"nativeCreateObject","(Ljava/lang/Class;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/Object;",(void*)nativeCreateObject}
};

//此函数通过调用RegisterNatives方法来注册我们的函数
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* getMethods,int methodsNum){
    jclass clazz;
    //找到声明native方法的类
    clazz = env->FindClass(className);
    if(clazz == NULL){
        return JNI_FALSE;
    }
    //注册函数 参数：java类 所要注册的函数数组 注册函数的个数
    if(env->RegisterNatives(clazz, getMethods, methodsNum) < 0){
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

static int registerNatives(JNIEnv* env){
    //指定类的路径，通过FindClass 方法来找到对应的类
    const char* className  = "com/smc/jnidemo/MainActivity";
    return registerNativeMethods(env,className,getMethods, sizeof(getMethods)/ sizeof(getMethods[0]));
}
//回调函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    JNIEnv* env = NULL;
    //获取JNIEnv
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);
    //注册函数 registerNatives ->registerNativeMethods ->env->RegisterNatives
    if(!registerNatives(env)){
        return -1;
    }
    //返回jni 的版本
    return JNI_VERSION_1_6;
}

